home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-06-27 | 28.2 KB | 1,298 lines | [TEXT/CWIE] |
- // =======================================================================
- // 3D Class Library, © Xilex Group
- // - ------------------------------------------------------------------- -
- // Written by Dmitry Boldyrev
- // =======================================================================
-
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #include "3dcl.h"
-
- WORD matrix[9];
- WORD *perspect;
- world3d world;
- viewPoint camera;
-
- struct
- {
- WORD startx;
- WORD endx;
- WORD startcol;
- WORD endcol;
- WORD x1;
- WORD y1;
- WORD x2;
- WORD y2;
- } points[480];
-
- extern UBYTE *thepic; // Holds the 256x256 texture image
-
- extern Rect rBounds;
-
- const char Onyx_Banner[] =
- "3D Class Library by Onyx Media Group." \
- "All rights reserved.";
-
- #define MIN(a, b) (((a)<(b))?(a):(b))
- #define MAX(a, b) (((a)>(b))?(a):(b))
-
- // =======================================================================
- // • dotProduct function definition •
- // =======================================================================
-
- WORD dotProduct(const vector3d *v1, const vector3d *v2)
- {
- return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
- }
-
- static void initPerspect()
- {
- perspect = new WORD [32768];
-
- for (WORD count = 0; count < 32768; count++)
- perspect[count] = 1024 * 64 / (count + 1);
- }
-
- static void delPerspect()
- {
- delete[] perspect;
- }
-
- // =======================================================================
- // • vertex class definitions •
- // =======================================================================
-
- vertex::vertex()
- {
- }
-
- static inline void subVectors(const vector3d *a, const vector3d *b, vector3d *c)
- {
- c->x = a->x - b->x;
- c->y = a->y - b->y;
- c->z = a->z - b->z;
- }
-
- // =======================================================================
- // project the point to the screen
- // =======================================================================
-
- void vertex::xform2d()
- {
- static vector3d vec;
-
- subVectors(&xyz, &camera.view, &vec);
-
- if (vec.z)
- {
- xy.x = ((vec.x<<10)/vec.z) + middle.h;
- xy.y = middle.v - ((vec.y<<10)/vec.z);
- } else
- {
- xy.x = vec.x;
- xy.y = vec.y;
- }
- }
-
- // =======================================================================
- // zero the normal for this point (used for gouraud shading)
- // =======================================================================
-
- void vertex::zeroNormal()
- {
- normal.x = 0;
- normal.y = 0;
- normal.z = 0;
-
- nCount = 0;
- }
-
- void vertex::setTo(WORD x, WORD y, WORD z, WORD inKind)
- {
- xyz.x = x;
- xyz.y = y;
- xyz.z = z;
-
- mKind = inKind;
-
- zeroNormal();
- xform2d();
- }
-
- vertex::vertex(WORD x, WORD y, WORD z, WORD inKind)
- {
- setTo(x, y, z, inKind);
- }
-
- // =======================================================================
- // translate (move) a point by (dX, dY, dZ)
- // =======================================================================
-
- void vertex::translate(WORD dX, WORD dY, WORD dZ)
- {
- }
-
- // =======================================================================
- // add (dX, dY, dZ) to the normal for this point
- // =======================================================================
-
- void vertex::addNormal(WORD dX, WORD dY, WORD dZ)
- {
- normal.x += dX;
- normal.y += dY;
- normal.z += dZ;
-
- nCount ++;
- }
-
- // =======================================================================
- // average the normal of this point
- // =======================================================================
-
- void vertex::avgNormal()
- {
- if (nCount)
- {
- normal.x /= nCount;
- normal.y /= nCount;
- normal.z /= nCount;
-
- WORD d = SQRT(SQR(normal.x) + SQR(normal.y) + SQR(normal.z));
-
- normal.x = (normal.x << 16) / d;
- normal.y = (normal.y << 16) / d;
- normal.z = (normal.z << 16) / d;
- }
- }
- // =======================================================================
- // rotate a point about its origin (faster method, *mat array
- // used to store sin/cos data that remains constant for all
- // points in a given object
- // =======================================================================
-
- void vertex::localRotate(matrix3d mat)
- {
- static vector3d local;
-
- local.x = (mat[0][0] * xyz.x + mat[0][1] * xyz.y + mat[0][2] * xyz.z) >> 16;
- local.y = (mat[1][0] * xyz.x + mat[1][1] * xyz.y + mat[1][2] * xyz.z) >> 16;
- local.z = (mat[2][0] * xyz.x + mat[2][1] * xyz.y + mat[2][2] * xyz.z) >> 16;
-
- xyz = local;
-
- xform2d();
- }
-
- vertex::~vertex()
- {
- }
-
- // =======================================================================
- // • polygon class definitions •
- // =======================================================================
-
- polygon::polygon()
- {
- }
-
- polygon::polygon(vertex *v1, vertex *v2, vertex *v3)
- {
- setTo(v1, v2, v3);
- }
-
- void polygon::setTo(vertex *v1, vertex *v2, vertex *v3)
- {
- register double i, j, k, d;
-
- p1 = v1;
- p2 = v2;
- p3 = v3;
-
- // Calculating the normal to the polygon
- i = (((p2->xyz.y - p1->xyz.y) * (p3->xyz.z - p1->xyz.z)) -
- ((p2->xyz.z - p1->xyz.z) * (p3->xyz.y - p1->xyz.y)));
-
- j = (((p2->xyz.z - p1->xyz.z) * (p3->xyz.x - p1->xyz.x)) -
- ((p2->xyz.x - p1->xyz.x) * (p3->xyz.z - p1->xyz.z)));
-
- k = (((p2->xyz.x - p1->xyz.x) * (p3->xyz.y - p1->xyz.y)) -
- ((p2->xyz.y - p1->xyz.y) * (p3->xyz.x - p1->xyz.x)));
-
- d = SQRT(SQR(i) + SQR(j) + SQR(k));
-
- i = (i / d * 32768);
- j = (j / d * 32768);
- k = (k / d * 32768);
-
- normal.setTo(i, j, k, isNormal);
- }
-
- // =======================================================================
- // average Z value of a polygon, used for depth sorting
- // =======================================================================
-
- WORD polygon::calcAvgZ()
- {
- return (averageZ = 32767 + ((p1->xyz.z + p2->xyz.z + p3->xyz.z) / 3));
- }
-
- void polygon::setNewOrigin(vertex *p)
- {
- p1->setNewOrigin(p);
- p2->setNewOrigin(p);
- p3->setNewOrigin(p);
-
- normal.setNewOrigin(p);
- }
-
- // =======================================================================
- // this function should be called for all polygons in an object,
- // following which point->avgNormals() should be called for all
- // points in an object. The object3d->setGNormals function takes
- // care of all of this...
- // =======================================================================
-
- void polygon::setGNormals()
- {
- p1->addNormal(normal.xyz.x, normal.xyz.y, normal.xyz.z);
- p2->addNormal(normal.xyz.x, normal.xyz.y, normal.xyz.z);
- p3->addNormal(normal.xyz.x, normal.xyz.y, normal.xyz.z);
- }
-
-
- void polygon::renderFlat()
- {
- }
-
- void polygon::renderGouraudTexMap()
- {
- }
-
- void polygon::renderWire()
- {
- ::ForeColor(whiteColor);
-
- ::MoveTo(p1->xy.x, p1->xy.y);
- ::LineTo(p2->xy.x, p2->xy.y);
- ::LineTo(p3->xy.x, p3->xy.y);
- ::LineTo(p1->xy.x, p1->xy.y);
-
- /*::ForeColor(greenColor);
- ::MoveTo(p1->xy.x, p1->xy.y);
- ::LineTo(normal.xy.x, normal.xy.y); */
- }
-
- void polygon::renderNone()
- {
- }
-
- #if GENERATINGCFM
- asm void limit_upoint(register upoint *p, register Rect *r);
- #pragma parameter limit_upoint(__r3, __r4)
- asm void limit_upoint(
- register upoint *p,
- register Rect *r)
- {
- lwz r5, p->x // r5 = p->x
- lha r6, r->left // r6 = r->left
- cmpw r5, r6 // p->x < r->left ?
- bge @1 // NO
- mr r5, r6 // r5 = r6
- stw r6, p->x // YES
- @1 lha r6, r->right // r6 = r->right
- cmpw r5, r6 // p->x > r->right ?
- ble @2 // NO
- mr r5, r6 // r5 = r6
- stw r6, p->x // YES
- @2 lwz r5, p->y // r5 = p->y
- lha r6, r->top // r6 = r->top
- cmpw r5, r6 // p->y < r->top ?
- bge @3 // NO
- mr r5, r6 // r5 = r6
- stw r6, p->y // YES
- @3 lha r6, r->bottom // r6 = r->bottom
- cmpw r5, r6 // p->y > r->bottom ?
- ble @4 // NO
- mr r5, r6 // r5 = r6
- stw r6, p->y // YES
- @4 blr
- }
- #else
- static void limit_upoint(
- register upoint *p,
- register Rect *r)
- {
- if (p->x < r->left) {
- p->x = r->left;
- } else
- if (p->x > r->right) {
- p->x = r->right;
- }
-
- if (p->y < r->top) {
- p->y = r->top;
- } else
- if (p->y > r->bottom) {
- p->y = r->bottom;
- }
- }
- #endif
-
- void polygon::renderTexMap()
- {
- register WORD x, mx, xcoord, ycoord, xstep, ystep, y;
- register upoint pTop, pMid, pBot;
- register UBYTE *src, *dest;
-
- if (p2->xy.y > p1->xy.y)
- {
- pTop = p1->xy; pBot = p2->xy;
- } else
- {
- pTop = p2->xy; pBot = p1->xy;
- }
- if (pTop.y > p3->xy.y)
- {
- pTop = p3->xy;
- if (p2->xy.y > p1->xy.y)
- {
- pMid = p1->xy; pBot = p2->xy;
- } else
- {
- pMid = p2->xy; pBot = p1->xy;
- }
- } else
- {
- if (pBot.y > p3->xy.y)
- {
- pMid = p3->xy;
- } else
- {
- pMid = pBot; pBot = p3->xy;
- }
- }
-
- limit_upoint(&pTop, &rBounds);
- limit_upoint(&pMid, &rBounds);
- limit_upoint(&pBot, &rBounds);
-
- // p3.x, p3.y, p3.c -> p1.x, p1.y, p1.c
-
- #if !GENERATINGCFM
- if (pBot.y - pTop.y)
- {
- #endif
- x = pTop.x << 8;
- mx = ((pBot.x - pTop.x) << 8) / (pBot.y - pTop.y);
-
- xcoord = pTop.u << 8;
- xstep = ((pBot.u - pTop.u) << 8) / (pBot.y - pTop.y);
-
- ycoord = pTop.v << 8;
- ystep = ((pBot.v - pTop.v) << 8) / (pBot.y - pTop.y);
-
- for (y = pTop.y; y < pBot.y; y++)
- {
- points[y].startx = x >> 8;
- points[y].x1 = xcoord >> 8;
- points[y].y1 = ycoord >> 8;
- points[y].endx = 0;
- points[y].x2 = 0;
- points[y].y2 = 0;
-
- x += mx;
- xcoord += xstep;
- ycoord += ystep;
- }
- #if !GENERATINGCFM
- }
- #endif
-
- // X1, p1.y, p1.c -> p2.x, p2.y, p2.c
- #if !GENERATINGCFM
- if (pMid.y - pTop.y)
- {
- #endif
- x = pTop.x << 8;
- mx = ((pMid.x - pTop.x) << 8) / (pMid.y - pTop.y);
-
- xcoord = pTop.u << 8;
- xstep = ((pMid.u - pTop.u) << 8) / (pMid.y - pTop.y);
-
- ycoord = pTop.v << 8;
- ystep = ((pMid.v - pTop.v) << 8) / (pMid.y - pTop.y);
-
- for (y = pTop.y; y < pMid.y; y++)
- {
- if (points[y].startx)
- {
- points[y].endx = x >> 8;
- points[y].x2 = xcoord >> 8;
- points[y].y2 = ycoord >> 8;
- } else
- {
- points[y].startx = x >> 8;
- points[y].x1 = xcoord >> 8;
- points[y].y1 = ycoord >> 8;
- }
- x += mx;
- xcoord += xstep;
- ycoord += ystep;
- }
- #if !GENERATINGCFM
- }
- #endif
- // p2.x, p2.y, p2.c -> p3.x, p3.y, p3.c
-
- #if !GENERATINGCFM
- if (pBot.y - pMid.y)
- {
- #endif
- x = pMid.x << 8;
- mx = ((pBot.x - pMid.x) << 8) / (pBot.y - pMid.y);
-
- xcoord = pMid.u << 8;
- xstep = ((pBot.u - pMid.u) << 8) / (pBot.y - pMid.y);
-
- ycoord = pMid.v << 8;
- ystep = ((pBot.v - pMid.v) << 8) / (pBot.y - pMid.y);
-
- for (y = pMid.y; y < pBot.y; y++)
- {
- if (points[y].startx)
- {
- points[y].endx = x >> 8;
- points[y].x2 = xcoord >> 8;
- points[y].y2 = ycoord >> 8;
- } else
- {
- points[y].startx = x >> 8;
- points[y].x1 = xcoord >> 8;
- points[y].y1 = ycoord >> 8;
- }
- x += mx;
- xcoord += xstep;
- ycoord += ystep;
- }
- #if !GENERATINGCFM
- }
- #endif
- // Do the drawing
-
- for (y = pTop.y; y < pBot.y; y++)
- {
- mx = points[y].endx - points[y].startx;
- if (mx)
- {
- if (mx < 0)
- {
- x = points[y].startx; points[y].startx = points[y].endx; points[y].endx = x;
- x = points[y].x1; points[y].x1 = points[y].x2; points[y].x2 = x;
- x = points[y].y1; points[y].y1 = points[y].y2; points[y].y2 = x;
- mx = -mx;
- }
-
- xcoord = points[y].x1 << 8;
- xstep = ((points[y].x2 - points[y].x1) << 8) / mx;
-
- ycoord = points[y].y1 << 8;
- ystep = ((points[y].y2 - points[y].y1) << 8) / mx;
-
- dest = (UBYTE*)baseAddr + y * rowBytes + points[y].startx;
- for (x = mx; x >= 0; x--)
- {
- *dest++ = thepic[(ycoord & 0xFFFFFF00) + (xcoord>>8)];
- xcoord += xstep;
- ycoord += ystep;
- }
- }
- }
- }
-
- void polygon::renderGouraud()
- {
- register WORD x, mx, c, mc, y;
- register upoint pTop, pMid, pBot;
- register Ptr base;
-
- /* if ((dotProduct(&p1->normal, &camera.view) <= 0) &&
- (dotProduct(&p2->normal, &camera.view) <= 0) &&
- (dotProduct(&p3->normal, &camera.view) <= 0))
- return;
- */
-
- p1->xy.c = ABS(dotProduct(&p1->normal, &camera.light)) >> 26;
- p2->xy.c = ABS(dotProduct(&p2->normal, &camera.light)) >> 26;
- p3->xy.c = ABS(dotProduct(&p3->normal, &camera.light)) >> 26;
-
- if (p2->xy.y > p1->xy.y)
- {
- pTop = p1->xy; pBot = p2->xy;
- } else
- {
- pTop = p2->xy; pBot = p1->xy;
- }
- if (pTop.y > p3->xy.y)
- {
- pTop = p3->xy;
- if (p2->xy.y > p1->xy.y)
- {
- pMid = p1->xy; pBot = p2->xy;
- } else
- {
- pMid = p2->xy; pBot = p1->xy;
- }
- } else
- {
- if (pBot.y > p3->xy.y)
- {
- pMid = p3->xy;
- } else
- {
- pMid = pBot; pBot = p3->xy;
- }
- }
-
- limit_upoint(&pTop, &rBounds);
- limit_upoint(&pMid, &rBounds);
- limit_upoint(&pBot, &rBounds);
-
- // p3.x, p3.y, p3.c -> p1.x, p1.y, p1.c
-
- #if !GENERATINGCFM
- if (pBot.y - pTop.y)
- {
- #endif
- x = pTop.x << 16;
- mx = ((pBot.x - pTop.x) << 16) / (pBot.y - pTop.y);
-
- c = pTop.c << 16;
- mc = ((pBot.c - pTop.c) << 16) / (pBot.y - pTop.y);
-
- for (y = pTop.y; y < pBot.y; y++)
- {
- points[y].startx = x >> 16;
- points[y].startcol = c >> 16;
- points[y].endx = points[y].endcol = 0;
-
- x += mx;
- c += mc;
- }
- #if !GENERATINGCFM
- }
- #endif
-
- // X1, p1.y, p1.c -> p2.x, p2.y, p2.c
- #if !GENERATINGCFM
- if (pMid.y - pTop.y)
- {
- #endif
- x = pTop.x << 16;
- mx = ((pMid.x - pTop.x) << 16) / (pMid.y - pTop.y);
-
- c = pTop.c << 16;
- mc = ((pMid.c - pTop.c) << 16) / (pMid.y - pTop.y);
-
- for (y = pTop.y; y < pMid.y; y++)
- {
- if (points[y].startx)
- {
- points[y].endx = x >> 16;
- points[y].endcol = c >> 16;
- } else
- {
- points[y].startx = x >> 16;
- points[y].startcol = c >> 16;
- }
- x += mx;
- c += mc;
- }
- #if !GENERATINGCFM
- }
- #endif
- // p2.x, p2.y, p2.c -> p3.x, p3.y, p3.c
-
- #if !GENERATINGCFM
- if (pBot.y - pMid.y)
- {
- #endif
- x = pMid.x << 16;
- mx = ((pBot.x - pMid.x) << 16) / (pBot.y - pMid.y);
-
- c = pMid.c << 16;
- mc = ((pBot.c - pMid.c) << 16) / (pBot.y - pMid.y);
-
- for (y = pMid.y; y < pBot.y; y++)
- {
- //if ((y >= 0) & (y < 480))
- if (points[y].startx)
- {
- points[y].endx = x >> 16;
- points[y].endcol = c >> 16;
- } else
- {
- points[y].startx = x >> 16;
- points[y].startcol = c >> 16;
- }
- x += mx;
- c += mc;
- }
- #if !GENERATINGCFM
- }
- #endif
- // Do the drawing
- register WORD start_x, end_x, start_col, end_col;
-
- base = baseAddr + pTop.y * rowBytes;
- for (y = pTop.y; y < pBot.y; y++)
- {
- start_x = points[y].startx; //xTop
- end_x = points[y].endx; //xBot
- #if !GENERATINGCFM
- if (end_x - start_x)
- {
- #endif
- start_col = points[y].startcol;
- end_col = points[y].endcol;
-
- if (end_x < start_x)
- {
- start_x = end_x; end_x = points[y].startx;
- start_col = end_col; end_col = points[y].startcol;
- }
- c = start_col << 16;
- mc = ((end_col - start_col) << 16) / (end_x - start_x);
-
- for (x = start_x; x < end_x; x++)
- {
- *(base+x) = c >> 16;
- c += mc;
- }
- base += rowBytes;
- #if !GENERATINGCFM
- }
- #endif
- }
-
- }
-
- void polygon::calcThetaPhi(vector3d v, WORD &r_theta, WORD &r_phi)
- {
- register double x, y, z, r, rho, theta, phi;
-
- x = normal.xyz.x / 65536.0;
- y = normal.xyz.y / 65536.0;
- z = normal.xyz.z / 65536.0;
-
- r = SQRT(SQR(x) + SQR(y));
- rho = SQRT(SQR(r) + SQR(z));
-
- phi = acos(z / r);
- theta = asin(y / r);
-
- r_theta = (theta / PI) * 65536.0;
- r_phi = (phi / PI) * 65536.0;
- }
-
- #define WRAP(x) ABS(x % 256)
- void polygon::applyTexture(WORD width, WORD height, WORD depth)
- {
- p1->xy.u = WRAP((p1->xyz.x<<8)/width);
- p1->xy.v = WRAP((p1->xyz.y<<8)/height);
-
- p2->xy.u = WRAP((p2->xyz.x<<8)/width);
- p2->xy.v = WRAP((p2->xyz.y<<8)/height);
-
- p3->xy.u = WRAP((p3->xyz.x<<8)/width);
- p3->xy.v = WRAP((p3->xyz.y<<8)/height);
-
- }
-
- // ====================================================================
- // must be called to initialize rendering proc
- // ====================================================================
-
- void polygon::renderPoly(BYTE method)
- {
- switch (method)
- {
- case sGouraudTexMap:
- renderGouraudTexMap();
- break;
- case sTexMap:
- renderTexMap();
- break;
- case sGouraud:
- renderGouraud();
- break;
- case sFlat:
- renderFlat();
- break;
- case sWire:
- renderWire();
- break;
- default:
- break;
- }
- }
-
- polygon::~polygon()
- {
- }
-
-
- // ====================================================================
- // • object3d class definitions •
- // ====================================================================
-
- object3d::object3d()
- {
- xDeg = 0;
- yDeg = 0;
- zDeg = 0;
- }
-
- WORD object3d::getPointNum(vertex *p)
- {
- register vertex *pt3d;
-
- count = 0;
- points.GoToFirstNode();
- while (pt3d = (vertex*) points.GetNextNode())
- {
- if (pt3d == p)
- return count;
- count++;
- }
- return -1;
- }
-
- vertex *object3d::getPointAddr(WORD pNum)
- {
- register WORD count;
- register vertex *pt3d;
-
- count = 0;
- points.GoToFirstNode();
- while (pt3d = (vertex*) points.GetNextNode())
- {
- if (count == pNum)
- return pt3d;
- count ++;
- }
- return 0;
- }
-
- // =======================================================================
- // binary format save routine
- // =======================================================================
-
- void object3d::save(char *fname)
- {
- FILE *fp = ::fopen(fname, "wb");
-
- objFileHeader header;
-
- // assumes fp has already been opened, so we can store multiple objects
- // in the same file
-
- header.numPoints = points.NumNodes();
- header.numPolys = polys.NumNodes();
-
- fwrite(&header, sizeof(objFileHeader), 1, fp);
-
- vertex *pt3d;
- points.GoToFirstNode();
- while (pt3d = (vertex*) points.GetNextNode())
- {
- fwrite(&pt3d->xyz, sizeof(vector3d), 1, fp);
- }
-
- polygon* poly;
- polyRec pRec;
-
- polys.GoToFirstNode();
- while (poly = (polygon*) polys.GetNextNode())
- {
- pRec.p1 = getPointNum(poly->p1);
- pRec.p2 = getPointNum(poly->p2);
- pRec.p3 = getPointNum(poly->p3);
- pRec.color = 0xFF;
- fwrite(&pRec, sizeof(polyRec), 1, fp);
- }
- fclose(fp);
- }
-
- void object3d::addLocalPoint(vertex *p)
- {
- // p->globalXform2origin(origin);
- points.AppendNode(p);
- }
-
- // =======================================================================
- // add a point whose coordinates are given as local to the origin of
- // this object to this objects list of points
- // =======================================================================
-
- void object3d::addLocalPoint(WORD x, WORD y, WORD z, WORD inKind)
- {
- addLocalPoint(new vertex(x, y, z, inKind));
- }
-
- // ====================================================================
- // add a local polygon (whose vertices are local points)
- // ====================================================================
-
- void object3d::addLocalPoly(polygon *pg)
- {
- polys.AppendNode(pg);
- addLocalPoint(&pg->normal);
- }
-
- void object3d::addLocalPoly(WORD p1, WORD p2, WORD p3)
- {
- addLocalPoly(new polygon(getPointAddr(p1), getPointAddr(p2), getPointAddr(p3)));
- }
-
- // =======================================================================
- // binary format load routine
- // =======================================================================
-
- void object3d::load(char *fname)
- {
- WORD numPoints, numPolys;
- FILE *fp = ::fopen(fname, "rb");
-
- objFileHeader header;
-
- // free old data
-
- points.FreeNodes();
- polys.FreeNodes();
-
- // assumes fp has already been opened, so we can store multiple objects
- // in the same file
-
- fread(&header, sizeof(objFileHeader), 1, fp);
-
- numPoints = header.numPoints;
- numPolys = header.numPolys;
-
- vector3d ptRec;
- for (count = 0; count < numPoints; count++)
- {
- fread(&ptRec, sizeof(vector3d), 1, fp);
- addLocalPoint(ptRec.x, ptRec.y, ptRec.z, isVertex);
- }
-
- polyRec pRec;
- for (count = 0; count < numPolys; count++)
- {
- fread(&pRec, sizeof(polyRec), 1, fp);
- addLocalPoly(pRec.p1, pRec.p2, pRec.p3);
- }
- fclose(fp);
- }
-
- void object3d::importASC(char *fname)
- {
- register FILE *inFile;
- register WORD tempInt, vertices, faces, // Considering only 2i model
- count, tempA, tempB, tempC;
- register char tempChar;
- register float tempX, tempY, tempZ;
- register char tempStr[255];
-
- inFile = fopen(fname, "rt");
- if (inFile == NULL)
- return;
-
- while (strncmp(tempStr, "Vertices", 8))
- {
- fscanf(inFile, "%s", tempStr);
- if (feof(inFile))
- return;
- }
-
- tempChar = fgetc(inFile);
- fscanf(inFile, "%d", &vertices);
- while (strncmp(tempStr, "Faces", 5))
- {
- fscanf(inFile, "%s", tempStr);
- if (feof(inFile))
- return;
- }
-
- tempChar = fgetc(inFile);
- fscanf(inFile, "%d", &faces);
-
- while (strncmp(tempStr, "Vertex", 6))
- {
- fscanf(inFile, "%s", tempStr);
- if (feof(inFile))
- return;
- }
- while (strncmp(tempStr, "list:", 5))
- {
- fscanf(inFile, "%s", tempStr);
- if (feof(inFile))
- return;
- }
-
- for (count = 0; count < vertices; count++)
- {
- while (strncmp(tempStr, "Vertex", 6))
- {
- fscanf(inFile, "%s", tempStr);
- if (feof(inFile))
- return;
- }
-
- fscanf(inFile, "%d", &tempInt);
- fscanf(inFile, "%s", tempStr);
- fscanf(inFile, "%s", tempStr);
- fscanf(inFile, "%f", &tempX);
- fscanf(inFile, "%s", tempStr);
- fscanf(inFile, "%f", &tempY);
- fscanf(inFile, "%s", tempStr);
- fscanf(inFile, "%f", &tempZ);
-
- addLocalPoint(tempX, tempY, tempZ, isVertex);
- }
-
- while (strncmp(tempStr, "Face", 4))
- {
- fscanf(inFile, "%s", tempStr);
- if (feof(inFile))
- return;
- }
-
- while (strncmp(tempStr, "list", 4))
- {
- fscanf(inFile, "%s", tempStr);
- if (feof(inFile))
- return;
- }
-
- for (count = 0; count < faces; count++)
- {
- while (strncmp(tempStr, "Face", 4))
- {
- fscanf(inFile, "%s", tempStr);
- if (feof(inFile))
- return;
- }
-
- fscanf(inFile, "%d", &tempInt);
- fscanf(inFile, "%s", tempStr);
-
- while (fgetc(inFile) != 'A');
- fgetc(inFile); // get the ':' character
- fscanf(inFile, "%d", &tempA); // get value for vertex A
-
- while (fgetc(inFile) != 'B');
- fgetc(inFile);
- fscanf(inFile, "%d", &tempB);
-
- while (fgetc(inFile) != 'C');
- fgetc(inFile);
- fscanf(inFile, "%d", &tempC);
-
- addLocalPoly(tempA, tempB, tempC);
- }
- fclose(inFile);
- }
-
- #define koeff 100
- void object3d::importV3D(char *fname)
- {
- register FILE *inFile;
- register WORD vertices, faces, count, tempA,
- tempB, tempC, tempD, color;
- register SINGLE tempX, tempY, tempZ;
- register char tempStr[255];
-
- inFile = fopen(fname, "rt");
- if (inFile == NULL)
- return;
-
- fscanf(inFile, "%s", tempStr);
- if (strncmp(tempStr, "3DG1", 4) != 0)
- return;
- fscanf(inFile, "%d", &vertices);
-
- for (count = 0; count < vertices; count++)
- {
- fscanf(inFile, "%f %f %f", &tempX, &tempY, &tempZ);
- addLocalPoint(tempX*koeff, tempY*koeff, tempZ*koeff, isVertex);
- }
-
- for (count = 0; ; count++)
- {
- fscanf(inFile, "%d", &faces);
- switch (faces)
- {
- case 1:
- fscanf(inFile, "%d %d", &tempA, &color);
- addLocalPoly(tempA, tempA, tempA);
- break;
- case 2:
- fscanf(inFile, "%d %d %d", &tempA, &tempB, &color);
- addLocalPoly(tempA, tempB, tempA);
- break;
- case 3:
- fscanf(inFile, "%d %d %d %d", &tempA, &tempB, &tempC, &color);
- addLocalPoly(tempA, tempB, tempC);
- break;
- case 4:
- fscanf(inFile, "%d %d %d %d %d", &tempA, &tempB, &tempC, &tempD, &color);
- addLocalPoly(tempA, tempB, tempC);
- addLocalPoly(tempC, tempD, tempA);
- break;
- default:
- fgets(tempStr, 255, inFile);
- break;
- }
- if (feof(inFile))
- break;
- }
- fclose(inFile);
- }
-
- // =======================================================================
- // rotate this object about it's origin
- // =======================================================================
-
- void object3d::localRotate()
- {
- register vertex *pt3d;
-
- points.GoToFirstNode();
- while (pt3d = (vertex*) points.GetNextNode())
- pt3d->localRotate(mat);
- }
-
- void object3d::applyTexture()
- {
- polygon *poly;
- WORD width, height, depth;
-
- calcBounds(width, height, depth);
-
- polys.GoToFirstNode();
- while (poly = (polygon*) polys.GetNextNode())
- poly->applyTexture(width, height, depth);
- }
-
- void object3d::calcBounds(WORD &width, WORD &height, WORD &depth)
- {
- register vertex *pt3d;
- register WORD minX, minY, minZ,
- maxX, maxY, maxZ;
-
- minX = minY = minZ = 32767;
- maxX = maxY = maxZ = -32767;
-
- points.GoToFirstNode();
- while (pt3d = (vertex*) points.GetNextNode())
- {
- if (pt3d->mKind == isVertex)
- {
- minX = MIN(minX, pt3d->xyz.x);
- minY = MIN(minY, pt3d->xyz.y);
- minZ = MIN(minZ, pt3d->xyz.z);
-
- maxX = MAX(maxX, pt3d->xyz.x);
- maxY = MAX(maxY, pt3d->xyz.y);
- maxZ = MAX(maxZ, pt3d->xyz.z);
- }
- }
- width = maxX - minX; height = maxY - minY; depth = maxZ - minZ;
- }
-
- #define TORAD(x) ((x) * PI / 180.0)
-
- void object3d::makeRotMatrix(WORD Xrot, WORD Yrot, WORD Zrot)
- {
- register double cXrot, cYrot, cZrot,
- sXrot, sYrot, sZrot;
-
- cXrot = cos(TORAD(Xrot)); cYrot = cos(TORAD(Yrot)); cZrot = cos(TORAD(Zrot));
- sXrot = sin(TORAD(Xrot)); sYrot = sin(TORAD(Yrot)); sZrot = sin(TORAD(Zrot));
-
- mat[0][0] = 65536 * (cYrot * cZrot);
- mat[0][1] = 65536 * (cZrot * sXrot * sYrot - sZrot * cXrot);
- mat[0][2] = 65536 * (-(cXrot * cZrot * sYrot + sXrot * sZrot));
- mat[1][0] = 65536 * (sZrot * cYrot);
- mat[1][1] = 65536 * (sXrot * sYrot * sZrot + cXrot * cZrot);
- mat[1][2] = 65536 * (-(sYrot * sZrot * cXrot) + sXrot * cZrot);
- mat[2][0] = 65536 * (sYrot);
- mat[2][1] = 65536 * (-sXrot * cYrot);
- mat[2][2] = 65536 * (cXrot * cYrot);
- }
-
- // =======================================================================
- // translate (move) this object
- // =======================================================================
-
- void object3d::translate(WORD dX, WORD dY, WORD dZ)
- {
- register vertex *pt3d;
-
- points.GoToFirstNode();
- while (pt3d = (vertex*) points.GetNextNode())
- pt3d->translate(dX, dY, dZ);
- }
-
- // =======================================================================
- // radix sort, peforms linear-time sorting on the polygons
- // =======================================================================
-
- void object3d::sortPlanes()
- {
- register polygon *poly;
- register UBYTE index;
- register WORD count;
-
- // Consider only the least significant radix
- polys.GoToFirstNode();
- while (poly = (polygon*) polys.GetNextNode())
- {
- index = (poly->calcAvgZ()) & 0x00FF;
- stack1[index].push(poly);
- }
-
- // Move shtuff from stack1 to stack2, considering second least
- // significant radix
- for (count = 255; count >= 0; count--)
- {
- while (!stack1[count].empty())
- {
- poly = (polygon*)stack1[count].pop();
- index = (poly->averageZ & 0xFF00) >> 8;
- stack2[index].push(poly);
- }
- }
- // Rebuild the list
- polys.ForgetNodes();
- for (count = 0; count <= 255; count++)
- {
- while (!stack2[count].empty())
- {
- polys.AppendNode(stack2[count].pop());
- }
- }
- }
-
- // =======================================================================
- // have this object set up its normal vectors needed for gouraud shading
- // =======================================================================
-
- void object3d::setGNormals()
- {
- register polygon *poly;
-
- polys.GoToFirstNode();
- while (poly = (polygon*) polys.GetNextNode())
- poly->setGNormals();
-
- vertex *pt3d;
-
- points.GoToFirstNode();
- while (pt3d = (vertex*) points.GetNextNode())
- {
- pt3d->avgNormal();
- }
- }
-
- void object3d::zeroGNormals()
- {
- register vertex *pt3d;
-
- points.GoToFirstNode();
- while (pt3d = (vertex*) points.GetNextNode())
- {
- pt3d->zeroNormal();
- }
- }
-
- // =======================================================================
- // universal display function that utilizes each polygon's shading
- // and facing data. This allows you to combine gouraud, flat, and
- // nonshaded polygons in the same object.
- // =======================================================================
-
- void object3d::display()
- {
- sortPlanes();
- register polygon *poly;
-
- polys.GoToFirstNode();
- while (poly = (polygon*) polys.GetNextNode())
- poly->renderPoly(sGouraud);
-
- }
-
- object3d::~object3d()
- {
- }
-
-
- // =======================================================================
- // • world3d class definitons •
- // =======================================================================
-
- world3d::world3d()
- {
- initSinCos();
- //initPerspect();
- }
-
- world3d::~world3d()
- {
- //delPerspect();
- }
-
- void world3d::insertObject(object3d *object)
- {
- objects.AppendNode(object);
- }
-
- void world3d::deleteObject(object3d *object, BOOL doDisposeIt)
- {
- objects.RemoveNode(object, doDisposeIt);
- }
-
- void world3d::globalRotate(WORD tX, WORD tY, WORD tZ)
- {
- }
-
- void world3d::draw()
- {
- register object3d *object;
-
- objects.GoToFirstNode();
- while (object = (object3d*) objects.GetNextNode())
- object->display();
- }
-
- viewPoint::viewPoint()
- {
- location.x = 0;
- location.y = 0;
- location.z = 0;
-
- light.x = 0;
- light.y = 0;
- light.z = 32767;
-
- view.x = 0;
- view.y = 0;
- view.z = 2300;
- }
-
- viewPoint::~viewPoint()
- {
- }
-